package org.intrasearch.core.io;

import sun.reflect.ReflectionFactory;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class DefaultExternalizableProvider<T extends Externalizable> implements ExternalizableProvider<T>
{
    private final Class<? extends T> type;
    private Constructor constructor;

    public DefaultExternalizableProvider(Class<? extends T> type)
    {
        this.type = type;
        initConstructor();
    }

    private void initConstructor()
    {
        ReflectionFactory factory = ReflectionFactory.getReflectionFactory();
        try
        {
            //heavy operation
            constructor = factory.newConstructorForSerialization(type, Object.class.getConstructor());
        }
        catch (NoSuchMethodException e)
        {
            throw new RuntimeException(e);
        }
    }

    public void writeExternal(T object, ObjectOutput output) throws IOException
    {
        object.writeExternal(output);
    }

    public T readExternal(ObjectInput input) throws IOException, ClassNotFoundException
    {
        T instance = createInstance(type);
        instance.readExternal(input);
        return instance;
    }

    private T createInstance(Class<? extends T> aClass)
    {
        try
        {
            return (T) constructor.newInstance();
        }
        catch (InvocationTargetException e)
        {
            throw new RuntimeException(e);
        }
        catch (InstantiationException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
    }
}
